// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.

namespace Microsoft.Samples.Commerce.Order.CommerceEntities
{
    using Microsoft.Commerce.Contracts;

    /// <summary>
    /// Class defines a Discount.
    /// </summary>
    public class Discount : ICommerceEntity
    {
        /// <summary>
        /// defines the model name for this commerce entity
        /// </summary>
        public const string ModelNameDefinition = "Discount";

        /// <summary>
        /// The commerce entity.
        /// </summary>
        private CommerceEntity commerceEntity;

        /// <summary>
        /// Initializes a new instance of the <see cref="Discount"/> class.
        /// </summary>
        public Discount()
        {
            this.commerceEntity = new CommerceEntity(Discount.ModelNameDefinition);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Discount"/> class.
        /// </summary>
        /// <param name="commerceEntity">The commerce entity.</param>
        public Discount(CommerceEntity commerceEntity)
        {
            this.commerceEntity = commerceEntity;
        }

        #region ICommerceEntity Members

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id of the entity.</value>
        public string Id
        {
            get { return this.commerceEntity.Id; }
            set { this.commerceEntity.Id = value; }
        }

        /// <summary>
        /// Gets or sets the type name of this object instance
        /// <remarks>Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type</remarks>
        /// </summary>
        /// <value></value>
        public string ModelName
        {
            get { return this.commerceEntity.ModelName; }
            set { this.commerceEntity.ModelName = value; }
        }

        /// <summary>
        /// Gets or sets this objects collection of Properties and their corresponding values
        /// </summary>
        /// <value></value>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Collection setting is required")]
        public CommercePropertyCollection Properties
        {
            get { return this.commerceEntity.Properties; }
            set { this.commerceEntity.Properties = value; }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the text describing the discount applied to the basket.
        /// </summary>
        /// <value>The display message.</value>
        public string DisplayMessage
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.DisplayMessage) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.DisplayMessage, value); }
        }

        /// <summary>
        /// Gets or sets the amount deducted.
        /// </summary>
        /// <value>The amount.</value>
        /// <remarks>
        /// This is a monetary amount deducted from the line item price, basket total, shipping
        /// charge etc. based on the Value property of this class.
        /// </remarks>
        public decimal? Amount
        {
            get { return (decimal?)this.commerceEntity.GetPropertyValue(PropertyName.Amount); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.Amount, value ?? null); }
        }

        /// <summary>
        /// Gets or sets the name of the current discount instance.
        /// </summary>
        /// <value>The discount name.</value>
        public string Name
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.Name) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.Name, value); }
        }

        /// <summary>
        /// Gets or sets a currency or percentage value for the discount.
        /// </summary>
        /// <value>The value.</value>
        public decimal? Value
        {
            get { return (decimal?)this.commerceEntity.GetPropertyValue(PropertyName.Value); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.Value, value ?? null); }
        }

        /// <summary>
        /// Gets or sets the meaning of the data stored in the Value property.
        /// </summary>
        /// <value>The type of the discount.</value>
        public int DiscountType
        {
            get { return (int)this.commerceEntity.GetPropertyValue(PropertyName.DiscountType); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.DiscountType, value); }
        }

        /// <summary>
        /// Gets or sets the discount priority or rank.
        /// </summary>
        /// <value>The priority.</value>
        /// <remarks>
        /// Discounts are applied in the order from the lowest priority (first) to the highest
        /// priority (last) in numerical number. Priority value must be greater than or equal to zero.
        /// </remarks>
        public int Priority
        {
            get { return (int)this.commerceEntity.GetPropertyValue(PropertyName.Priority); }
            set { this.commerceEntity.SetPropertyValue(PropertyName.Priority, value); }
        }

        /// <summary>
        /// Gets or sets the code that the current discount is associated with (if applicable).
        /// </summary>
        /// <value>The promo code.</value>
        /// <remarks>
        /// The PromoCode is a string that the customer provides to redeem a PromoCode enabled discount.
        /// For discounts not associated with a PromoCode this property will be null.
        /// </remarks>
        public string PromoCode
        {
            get { return this.commerceEntity.GetPropertyValue(PropertyName.PromoCode) as string; }
            set { this.commerceEntity.SetPropertyValue(PropertyName.PromoCode, value); }
        }

        #endregion

        #region Implicit operators
        /// <summary>
        /// Toes the user profile.
        /// </summary>
        /// <param name="commerceEntity">The commerce entity.</param>
        /// <returns></returns>
        public static implicit operator Discount(CommerceEntity commerceEntity)
        {
            System.Diagnostics.Debug.Assert(Discount.ModelNameDefinition.Equals(commerceEntity.ModelName), "Unexpected model name");
            return new Discount(commerceEntity);
        }
        #endregion

        /// <summary>
        /// Required so that the Builders can convert to the Multi-channel Commerce Foundation CommerceEntity base type using <see cref="ModelName"/>
        /// </summary>
        /// <returns>This instances base type</returns>
        public CommerceEntity ToCommerceEntity()
        {
            return this.commerceEntity;
        }

        #region Property key names

        /// <summary>
        /// Names of the properties exposed by this commerce entity.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Needed for external access"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors", Justification = "Cannot make it private as it cannot be derived from")]
        public class PropertyName : CommerceEntity.PropertyName
        {
            /// <summary>
            /// The name of the DisplayMessage property for a Discount.
            /// </summary>
            public const string DisplayMessage = "DisplayMessage";

            /// <summary>
            /// The name of the Amount property for a Discount.
            /// </summary>
            public const string Amount = "Amount";

            /// <summary>
            /// The name of the Name property for a Discount.
            /// </summary>
            public const string Name = "Name";

            /// <summary>
            /// The name of the Value property for a Discount.
            /// </summary>
            public const string Value = "Value";

            /// <summary>
            /// The name of the DiscountType property for a Discount.
            /// </summary>
            public const string DiscountType = "DiscountType";

            /// <summary>
            /// The name of the Priority property for a Discount.
            /// </summary>
            public const string Priority = "Priority";

            /// <summary>
            /// The name of the PromoCode property for a Discount.
            /// </summary>
            public const string PromoCode = "PromoCode";
        }

        #endregion
    }
}
